#!/usr/bin/env node

// ============================================================================
// 测试运行脚本
// ============================================================================

const { spawn } = require('child_process')
const path = require('path')
const fs = require('fs')

// 解析命令行参数
const args = process.argv.slice(2)
const options = {
  watch: args.includes('--watch') || args.includes('-w'),
  coverage: args.includes('--coverage') || args.includes('-c'),
  verbose: args.includes('--verbose') || args.includes('-v'),
  silent: args.includes('--silent') || args.includes('-s'),
  updateSnapshots: args.includes('--updateSnapshots') || args.includes('-u'),
  testNamePattern: getArgValue('--testNamePattern') || getArgValue('-t'),
  testPathPattern: getArgValue('--testPathPattern') || getArgValue('-p'),
  project: getArgValue('--project'),
  maxWorkers: getArgValue('--maxWorkers') || getArgValue('-j'),
  bail: args.includes('--bail'),
  detectOpenHandles: args.includes('--detectOpenHandles'),
  forceExit: args.includes('--forceExit')
}

function getArgValue(argName) {
  const index = args.indexOf(argName)
  return index !== -1 && index + 1 < args.length ? args[index + 1] : null
}

// 构建Jest命令
function buildJestCommand() {
  const jestArgs = []

  // 基础配置
  jestArgs.push('--config', 'jest.config.js')

  // 项目选择
  if (options.project) {
    jestArgs.push('--selectProjects', options.project)
  }

  // 监听模式
  if (options.watch) {
    jestArgs.push('--watch')
  }

  // 覆盖率
  if (options.coverage) {
    jestArgs.push('--coverage')
  }

  // 详细输出
  if (options.verbose) {
    jestArgs.push('--verbose')
  }

  // 静默模式
  if (options.silent) {
    jestArgs.push('--silent')
  }

  // 更新快照
  if (options.updateSnapshots) {
    jestArgs.push('--updateSnapshot')
  }

  // 测试名称模式
  if (options.testNamePattern) {
    jestArgs.push('--testNamePattern', options.testNamePattern)
  }

  // 测试路径模式
  if (options.testPathPattern) {
    jestArgs.push(options.testPathPattern)
  }

  // 最大工作进程
  if (options.maxWorkers) {
    jestArgs.push('--maxWorkers', options.maxWorkers)
  }

  // 遇到失败时停止
  if (options.bail) {
    jestArgs.push('--bail')
  }

  // 检测打开的句柄
  if (options.detectOpenHandles) {
    jestArgs.push('--detectOpenHandles')
  }

  // 强制退出
  if (options.forceExit) {
    jestArgs.push('--forceExit')
  }

  return jestArgs
}

// 运行测试
function runTests() {
  const jestArgs = buildJestCommand()
  
  console.log('🧪 运行测试...')
  console.log(`命令: npx jest ${jestArgs.join(' ')}`)
  console.log('')

  const jest = spawn('npx', ['jest', ...jestArgs], {
    stdio: 'inherit',
    shell: true,
    cwd: process.cwd()
  })

  jest.on('close', (code) => {
    if (code === 0) {
      console.log('\n✅ 所有测试通过!')
      
      // 如果启用了覆盖率，显示覆盖率报告路径
      if (options.coverage) {
        const coverageDir = path.join(process.cwd(), 'coverage')
        if (fs.existsSync(coverageDir)) {
          console.log(`📊 覆盖率报告: ${path.join(coverageDir, 'lcov-report/index.html')}`)
        }
      }
    } else {
      console.log(`\n❌ 测试失败，退出码: ${code}`)
      process.exit(code)
    }
  })

  jest.on('error', (error) => {
    console.error('❌ 运行测试时出错:', error)
    process.exit(1)
  })
}

// 显示帮助信息
function showHelp() {
  console.log(`
微博爬虫客户端测试运行器

用法:
  node scripts/test.js [选项]

选项:
  -w, --watch              监听模式，文件变化时自动重新运行测试
  -c, --coverage           生成测试覆盖率报告
  -v, --verbose            详细输出测试结果
  -s, --silent             静默模式，只显示错误
  -u, --updateSnapshots    更新快照
  -t, --testNamePattern    按测试名称模式过滤
  -p, --testPathPattern    按测试文件路径模式过滤
  --project <name>         运行指定项目的测试 (main|renderer)
  -j, --maxWorkers <num>   最大工作进程数
  --bail                   遇到第一个失败测试时停止
  --detectOpenHandles      检测可能导致Jest挂起的打开句柄
  --forceExit              强制Jest在测试完成后退出
  -h, --help               显示帮助信息

示例:
  node scripts/test.js                           # 运行所有测试
  node scripts/test.js --watch                   # 监听模式
  node scripts/test.js --coverage                # 生成覆盖率报告
  node scripts/test.js --project renderer        # 只运行渲染进程测试
  node scripts/test.js -t "Button"               # 运行包含"Button"的测试
  node scripts/test.js -p "components"           # 运行components目录下的测试
  node scripts/test.js --watch --verbose         # 监听模式 + 详细输出
`)
}

// 检查环境
function checkEnvironment() {
  // 检查Jest配置文件
  const jestConfig = path.join(process.cwd(), 'jest.config.js')
  if (!fs.existsSync(jestConfig)) {
    console.error('❌ 找不到Jest配置文件: jest.config.js')
    process.exit(1)
  }

  // 检查测试目录
  const testDirs = [
    'src/renderer/__tests__',
    'src/renderer/components/__tests__',
    'src/renderer/hooks/__tests__',
    'src/renderer/pages/__tests__',
    'src/renderer/store/__tests__',
    'src/renderer/utils/__tests__',
    'src/main/__tests__'
  ]

  let hasTests = false
  for (const dir of testDirs) {
    const fullPath = path.join(process.cwd(), dir)
    if (fs.existsSync(fullPath)) {
      const files = fs.readdirSync(fullPath)
      if (files.some(file => file.endsWith('.test.ts') || file.endsWith('.test.tsx'))) {
        hasTests = true
        break
      }
    }
  }

  if (!hasTests) {
    console.warn('⚠️  警告: 没有找到测试文件')
  }
}

// 主函数
function main() {
  if (args.includes('--help') || args.includes('-h')) {
    showHelp()
    return
  }

  console.log('🔍 检查测试环境...')
  checkEnvironment()

  runTests()
}

// 处理未捕获的异常
process.on('uncaughtException', (error) => {
  console.error('❌ 未捕获的异常:', error)
  process.exit(1)
})

process.on('unhandledRejection', (reason) => {
  console.error('❌ 未处理的Promise拒绝:', reason)
  process.exit(1)
})

// 运行
main()
